package com.dems.service.org.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dems.core.enumerate.ResEnum;
import com.dems.core.exception.LoanassistRuntimeException;
import com.dems.core.util.BeanCopyUtils;
import com.dems.dao.dataobject.*;
import com.dems.dao.mapper.la.*;
import com.dems.domain.enumerate.UserTypeEnum;
import com.dems.domain.org.*;
import com.dems.service.org.OrgService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class OrgServiceImpl implements OrgService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private StaffMapper staffMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private DeptStaffMapper deptStaffMapper;

    @Autowired
    private StaffRoleMapper staffRoleMapper;

    @Autowired
    private MenuMapper menuMapper;


    @Override
    public List<DeptDto> deptList(DeptDto deptDto, User loanassistUser) {

        List<Dept> deptList = deptMapper.selectList(deptDto.getSuperId());
        List<DeptDto> deptDtoList = new ArrayList<>();
        deptList.forEach(item -> {
            DeptDto deptDtoItem = new DeptDto();
            BeanUtils.copyProperties(item, deptDtoItem);
            if (StringUtils.isNotBlank(item.getCallLineInfo())) {
                deptDtoItem.setCallLineInfo(JSON.parseObject(item.getCallLineInfo()));
            }
            deptDtoList.add(deptDtoItem);
        });
        return deptDtoList;
    }

    @Override
    public List<DeptStaffDto> deptStaffList(DeptStaffDto deptStaffDto, User loanassistUser) {
        List<DeptStaff> staffList = deptStaffMapper.selectByDeptId(deptStaffDto.getDeptId());

        if (CollectionUtils.isEmpty(staffList)) {
            return null;
        }
        List<String> userIds = staffList.stream().map(DeptStaff::getUserId).distinct().collect(Collectors.toList());
        List<DeptStaffDto> deptStaffDtoList = BeanCopyUtils.copyListProperties(staffList, DeptStaffDto::new);

        List<Long> deptIdList = deptStaffDtoList.stream().map(DeptStaffDto::getDeptId).distinct().collect(Collectors.toList());
        List<Dept> deptList = deptMapper.selectByIdList(deptIdList);

        Map<Long, Dept> deptMap = deptList.stream().collect(
                Collectors.toMap(Dept::getId, Function.identity(), (x1, x2) -> x1));

        List<StaffRole> staffRoleList = staffRoleMapper.selectByUserIdList(staffList.stream()
                .map(DeptStaff::getUserId).collect(Collectors.toList()));

        Map<String, StaffRole> staffRoleMap = new HashMap<>();

        if (CollectionUtils.isNotEmpty(staffRoleList)) {
            staffRoleMap = staffRoleList.stream().collect(Collectors.toMap(StaffRole::getUserId, Function.identity(), (x1, x2) -> x1));
        }

        Map<String, StaffRole> finalStaffRoleMap = staffRoleMap;
        deptStaffDtoList.forEach(item -> {
            if (StringUtils.isNotBlank(item.getProfile())) {
                JSONObject profileJson = JSON.parseObject(item.getProfile());
                item.setSipAccount(profileJson.getString("sipAccount"));
                if(profileJson.get("number") != null){
                    item.setNumber(profileJson.getString("number"));
                }
                if(profileJson.get("gid") != null){
                    item.setGid(profileJson.getLong("gid"));
                }
                item.setProfile(null);
            }
            if (deptMap.containsKey(item.getDeptId())) {
                item.setDeptName(deptMap.get(item.getDeptId()).getDeptName());
            }
            if (finalStaffRoleMap.containsKey(item.getUserId())) {
                item.setRoleCodeList(Arrays.asList(finalStaffRoleMap.get(item.getUserId()).getStaffRole().split(",")));
            }
        });
        return deptStaffDtoList;
    }

    /**
     * 删除部门
     * 1、校验部门成员是否还有关系
     * @param deptDto
     * @param loanassistUser
     * @return
     */
    @Override
    public Integer deleteDept(DeptDto deptDto, User loanassistUser) {

        if (null == deptDto.getId()) {
            return 0;
        }

        List<DeptStaff> deptStaffList = deptStaffMapper.selectByDeptId(deptDto.getId());
        if (CollectionUtils.isNotEmpty(deptStaffList)) {
            throw new LoanassistRuntimeException(ResEnum.PROCESSING, "该部门还有关联员工，请调整好员工后再删除！");
        }
        List<Dept> deptList = deptMapper.selectList(deptDto.getId());
        if (CollectionUtils.isNotEmpty(deptList)) {
            throw new LoanassistRuntimeException(ResEnum.PROCESSING, "该部门还有子部门，请调整好子部门后再删除！");
        }

        Dept dept = new Dept();

        dept.setId(deptDto.getId());
        dept.setUpdateBy(loanassistUser.getName());
        dept.setUpdateOpenId(loanassistUser.getOpenId());
        dept.setUpdateUserId(loanassistUser.getUserId());

        return deptMapper.deleteByPrimaryKey(dept);
    }

    @Override
    public List<DeptStaffDto> saveDeptStaff(List<DeptStaffDto> deptStaffDtoList, User loanassistUser) {

        List<DeptStaff> deptStaffList = BeanCopyUtils.copyListProperties(deptStaffDtoList, DeptStaff::new);

        List<DeptStaff> dupData = deptStaffMapper.selectByUserIdList(deptStaffList.stream().map(DeptStaff::getUserId).collect(Collectors.toList()));

        if (CollectionUtils.isNotEmpty(dupData)) {
            log.info("saveDeptStaff dup {}", JSON.toJSONString(dupData));
            throw new LoanassistRuntimeException("以下员工重复添加, " +
                    dupData.stream().map(DeptStaff::getName).collect(Collectors.toList()) +
                    ", 请检查");
        }

        deptStaffList.forEach(item-> {
            item.setCreateBy(loanassistUser.getName());
            item.setCreateOpenId(loanassistUser.getOpenId());
            item.setCreateUserId(loanassistUser.getUserId());
        });
        deptStaffMapper.insertBatch(deptStaffList);
        return null;
    }

    @Override
    public Integer deleteDeptStaff(DeptStaffDto deptStaffDto, User loanassistUser) {
        return deptStaffMapper.deleteByPrimaryKey(deptStaffDto.getId());
    }

    @Override
    public List<StaffDto> staffList(StaffDto staffDto, User loanassistUser) {
        return null;
    }

    @Override
    public List<RoleDto> roleList(RoleDto roleDto, User loanassistUser) {
        List<Role> roleList = roleMapper.selectList();
        return BeanCopyUtils.copyListProperties(roleList, RoleDto::new);
    }
    @Override
    public List<StaffRoleDto> staffRoleList(RoleDto roleDto, User loanassistUser) {
        List<StaffRole> staffRoleList = staffRoleMapper.selectList(roleDto.getRoleCode(), null);

        List<StaffRoleDto> staffRoleDtoList = BeanCopyUtils.copyListProperties(staffRoleList, StaffRoleDto::new);

        staffRoleDtoList.forEach(item -> {
            if (StringUtils.isNotBlank(item.getProfile())) {
                JSONObject profileJson = JSON.parseObject(item.getProfile());
                item.setSipAccount(profileJson.getString("sipAccount"));
                item.setProfile(null);
            }
        });

        return staffRoleDtoList;
    }

    @Override
    public Integer saveStaffRole(List<StaffRoleDto> staffRoleDtoList, User loanassistUser) {
        // 重复人员角色剔除
        List<StaffRole> staffRoleList = new ArrayList<>();
        for (StaffRoleDto item : staffRoleDtoList) {
            StaffRole dupData = staffRoleMapper.selectByUserIdRoleCode(item.getUserId(), item.getRoleCode());
            if (null != dupData) {
                continue;
            }
            item.setCreateBy(loanassistUser.getName());
            item.setCreateOpenId(loanassistUser.getOpenId());
            item.setCreateUserId(loanassistUser.getUserId());

            StaffRole staffRole = new StaffRole();
            BeanUtils.copyProperties(item, staffRole);
            staffRoleList.add(staffRole);
        }
        if (CollectionUtils.isEmpty(staffRoleList)) {
            return 0;
        }
        staffRoleMapper.insertBatch(staffRoleList);
        return 1;
    }


    @Override
    public Integer deleteStaffRole(StaffRoleDto staffRoleDto, User loanassistUser) {
        return staffRoleMapper.deleteByPrimaryKey(staffRoleDto.getId());
    }

    @Override
    public DeptDto saveDept(DeptDto deptDto, User loanassistUser) {
        if (!UserTypeEnum.checkTypeRole(loanassistUser.getUserType(),
                loanassistUser.getRoleCodeList(),
                UserTypeEnum.T, UserTypeEnum.M, UserTypeEnum.CALL_LINE_MANAGER)) {
            throw new LoanassistRuntimeException("当前用户无权限操作，请核实");
        }

        // 检查部门名称重复
        if (deptDto.getId() == null) {
            Dept dupDept = deptMapper.selectByDeptName(deptDto.getDeptName());
            if (dupDept != null) {
                throw new LoanassistRuntimeException("该部门已存在，请核实");
            }
        }

        // 更新
        if (deptDto.getId() != null) {
            deptDto.setUpdateUserId(loanassistUser.getUserId());
            deptDto.setUpdateOpenId(loanassistUser.getOpenId());
            deptDto.setUpdateBy(loanassistUser.getName());
            deptDto.setUpdateTime(new Date());
        } else {
            deptDto.setCreateUserId(loanassistUser.getUserId());
            deptDto.setCreateOpenId(loanassistUser.getOpenId());
            deptDto.setCreateBy(loanassistUser.getName());
            deptDto.setCreateTime(new Date());
        }
        Dept dept = new Dept();

        BeanUtils.copyProperties(deptDto, dept);

        if (deptDto.getCallLineInfo() != null) {
            dept.setCallLineInfo(deptDto.getCallLineInfo().toJSONString());
        }

        if (StringUtils.isNotBlank(deptDto.getSupervisorIds())) {
            List<DeptStaff> deptStaffList = deptStaffMapper.selectByDeptId(deptDto.getId());
            List<DeptStaff> deptStaffListSuper = deptStaffMapper.selectByDeptId(deptDto.getSuperId());
            List<String> staffList = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(deptStaffList)) {
                staffList = deptStaffList.stream().map(DeptStaff::getUserId).collect(Collectors.toList());
            }

            if (CollectionUtils.isNotEmpty(deptStaffListSuper)) {
                staffList.addAll(deptStaffListSuper.stream().map(DeptStaff::getUserId).collect(Collectors.toList()));
            }

            if (!staffList.contains(deptDto.getSupervisorIds())) {
                throw new LoanassistRuntimeException(ResEnum.PROCESSING, "主管不在部门成员中，请核实");
            }
        }

        if (dept.getId() == null) {
            deptMapper.insertSelective(dept);
            deptDto.setId(dept.getId());
        } else {
            Dept dept1 = deptMapper.selectByPrimaryKey(dept.getId());
            if(dept1.getCallLineInfo() != null && dept.getCallLineInfo() != null){
                JSONObject obj = JSON.parseObject(dept1.getCallLineInfo());
                obj.putAll(JSON.parseObject(dept.getCallLineInfo()));
                dept.setCallLineInfo(obj.toJSONString());
            }
            deptMapper.updateByPrimaryKeySelective(dept);
        }

        return deptDto;
    }

    @Override
    public RoleDto saveRole(RoleDto roleDto, User loanassistUser) {
        return roleDto;
    }
    @Override
    public List<MenuDto> menuList(MenuDto menuDto, User loanassistUser) {
        List<Menu> menuList = menuMapper.selectList();

        List<MenuDto> menuDtoList = new ArrayList<>();

        menuList.forEach(item -> {
            MenuDto menuDtoItem = new MenuDto();
            BeanUtils.copyProperties(item, menuDtoItem);
            if (StringUtils.isNotBlank(item.getRoleCodeList())) {
                menuDtoItem.setRoleCodeList(JSON.parseArray(item.getRoleCodeList(), String.class));
            }
            menuDtoList.add(menuDtoItem);
        });
        return menuDtoList;
    }

    @Override
    public MenuDto saveMenu(MenuDto menuDto, User loanassistUser) {

        Menu dbMenu = menuMapper.selectByCode(menuDto.getMenuCode());

        if (dbMenu != null) {
            menuDto.setId(dbMenu.getId());
        } else {
            menuDto.setId(null);
        }

        // 更新
        if (menuDto.getId() != null) {
            menuDto.setUpdateUserId(loanassistUser.getUserId());
            menuDto.setUpdateOpenId(loanassistUser.getOpenId());
            menuDto.setUpdateBy(loanassistUser.getName());
            menuDto.setUpdateTime(new Date());
        } else {
            menuDto.setCreateUserId(loanassistUser.getUserId());
            menuDto.setCreateOpenId(loanassistUser.getOpenId());
            menuDto.setCreateBy(loanassistUser.getName());
            menuDto.setCreateTime(new Date());
        }
        Menu menu = new Menu();

        BeanUtils.copyProperties(menuDto, menu);

        menu.setRoleCodeList(JSON.toJSONString(menuDto.getRoleCodeList()));

        if (menu.getId() == null) {
            menuMapper.insertSelective(menu);
            menuDto.setId(menu.getId());
        } else {
            menuMapper.updateByPrimaryKeySelective(menu);
        }

        return menuDto;
    }

    /**
     * userMenuList
     * @param menuDto
     * @param loanassistUser
     * @return
     */
    @Override
    public List<String> userMenuList(MenuDto menuDto, User loanassistUser) {
        loanassistUser = userMapper.selectByPrimaryKey(loanassistUser.getUserId());

        List<StaffRole> staffRoleList = staffRoleMapper.selectByUserId(loanassistUser.getUserId());

        List<String> userTypeList = new ArrayList<>();
        log.info("userTypeList {}", JSON.toJSONString(userTypeList));
        if (CollectionUtils.isNotEmpty(staffRoleList)) {
            List<String> roleCodeList = staffRoleList.stream().map(StaffRole::getRoleCode).collect(Collectors.toList());
            log.info("roleCodeList {}", JSON.toJSONString(roleCodeList));
            if (CollectionUtils.isNotEmpty(roleCodeList)) {
                userTypeList.addAll(roleCodeList);
            }
        }
        List<Menu> menuList = menuMapper.selectByRoleCode(userTypeList);

        return menuList.stream().map(Menu::getMenuCode).collect(Collectors.toList());
    }

    /**
     * 设置部门员工角色
     * @param deptStaffDto
     * @param loanassistUser
     * @return
     */
    @Override
    public Integer saveDeptStaffRole(DeptStaffDto deptStaffDto, User loanassistUser) {
        // 员工岗位角色
        List<StaffRoleDto> staffRoleDtoList = new ArrayList<>();
        if (CollectionUtils.isEmpty(deptStaffDto.getRoleCodeList())) {
            return 0;
        }

        // 如果是主管，则校验当前部门所有成员是否已经存在主管岗位
        if (UserTypeEnum.checkTypeRole(null, deptStaffDto.getRoleCodeList(), UserTypeEnum.L1, UserTypeEnum.M, UserTypeEnum.VL, UserTypeEnum.BIZ_VISIT_L)) {
            List<DeptStaffDto> deptStaffDtoList = deptStaffList(deptStaffDto, loanassistUser);
            // 权限列表中存在已经是主管的成员，则禁止
            deptStaffDtoList = deptStaffDtoList.stream()
                    .filter(item -> (CollectionUtils.isNotEmpty(item.getRoleCodeList()))
                            && UserTypeEnum.checkTypeRole(null, item.getRoleCodeList(), UserTypeEnum.L1, UserTypeEnum.M, UserTypeEnum.VL, UserTypeEnum.BIZ_VISIT_L))
                    .collect(Collectors.toList());

            deptStaffDtoList = deptStaffDtoList.stream().filter(item -> !item.getUserId().equals(deptStaffDto.getUserId()))
                    .collect(Collectors.toList());

            if (CollectionUtils.isNotEmpty(deptStaffDtoList)) {
                throw new LoanassistRuntimeException(ResEnum.PROCESSING, "组员中存在主管角色，请先取消原来主管角色");
            }
        }

        if (UserTypeEnum.checkTypeRole(null, deptStaffDto.getRoleCodeList(), UserTypeEnum.L1, UserTypeEnum.M, UserTypeEnum.VL, UserTypeEnum.BIZ_VISIT_L)) {
            Dept dept = new Dept();
            dept.setId(deptStaffDto.getDeptId());
            dept.setSupervisorIds(deptStaffDto.getUserId());
            dept.setUpdateUserId(loanassistUser.getUserId());
            dept.setUpdateBy(loanassistUser.getName());
            dept.setUpdateOpenId(loanassistUser.getOpenId());
            deptMapper.updateByPrimaryKeySelective(dept);
        }

        List<StaffRole> dupData = staffRoleMapper.selectByUserId(deptStaffDto.getUserId());

        deptStaffDto.getRoleCodeList().forEach(subItem -> {
            StaffRoleDto staffRoleDto = new StaffRoleDto();
            staffRoleDto.setUserId(deptStaffDto.getUserId());
            staffRoleDto.setRoleCode(subItem);
            staffRoleDtoList.add(staffRoleDto);
        });

        dupData = dupData.stream().filter(item -> !deptStaffDto.getRoleCodeList().contains(item.getRoleCode()))
                .collect(Collectors.toList());

        if (CollectionUtils.isNotEmpty(dupData)) {
            dupData.forEach(item -> staffRoleMapper.deleteByPrimaryKey(item.getId()));
        }
        saveStaffRole(staffRoleDtoList, loanassistUser);
        return 1;
    }
}
